﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using Setup.Entities.AppFinder;
using Setup.Helpers;

namespace Setup.Controls
{
    public partial class AppFinder : UserControl
    {
        public event EventHandler Cancel;
        private const int TheOperationWasCanceledByTheUser = -2147467259;
        private AppFinderHelper _helper;
        private bool needInstallation;
        public bool IsComplete { get; set; }
        public string InstalledPath { get; set; }

        public AppInfo ApplicationInfo { get; set; }

        public AppFinder()
        {
            InitializeComponent();

            Cancel += OnCancel;

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;

            backgroundWorker2.DoWork += backgroundWorker2_DoWork;
            backgroundWorker2.ProgressChanged += backgroundWorker2_ProgressChanged;

            linkLabel1.LinkClicked += linkLabel1_LinkClicked;
        }

        void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(ApplicationInfo.ApplicationInfoUrl);
        }

        void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var eventArgs = e.UserState as AppFinderHelperEventArgs;
            if (eventArgs == null)
                return;

            switch (eventArgs.Status)
            {
                case AppFinderStatus.DownloadingStarted:
                    label2.Text = "Downloading...";
                    progressBar1.Value = 0;
                    button1.Enabled = true;
                    button1.Text = "Cancel";
                    break;
                case AppFinderStatus.ErrorWhenDownloading:
                    label2.Text = e.UserState.ToString();
                    progressBar1.Value = 0;
                    button1.Enabled = false;
                    break;
                case AppFinderStatus.DownloadingIsFinished:
                    label2.Text = "Download has been finished.";
                    progressBar1.Value = 100;
                    button1.Enabled = false;
                    break;
                case AppFinderStatus.VerifyingDownloadedFile:
                    label2.Text = "Validating installation files...";
                    button1.Enabled = false;
                    break;
                case AppFinderStatus.DownloadedFilesWasNotVerified:
                    label2.Text = "Invalid installation files.";
                    break;
                case AppFinderStatus.DownloadedFileWasSuccessfullyVerified:
                    label2.Text = "Installation files are correct.";
                    progressBar1.Value = 100;
                    break;
                case AppFinderStatus.SearchingForInstallion:
                    label2.Text = "Searching for previously installed version...";
                    progressBar1.Value = 0;
                    break;
                case AppFinderStatus.InstallationStarted:
                    label2.Text = "Installation started...";
                    progressBar1.Value = 0;
                    IsComplete = true;
                    break;
                case AppFinderStatus.InstallationFound:
                    label2.Text = "Installation found.";
                    progressBar1.Value = 100;
                    button1.Enabled = false;
                    InstalledPath = eventArgs.Message;
                    IsComplete = true;
                    break;
                case AppFinderStatus.InstallationCanceledByUser:
                    label2.Text = "Canceled by you";
                    button1.Enabled = false;
                    break;
                case AppFinderStatus.ActivateInstallation:
                    needInstallation = true;
                    label2.Text = "Please start installation by clicking button to the right.";
                    button1.Text = "Install";
                    button1.Enabled = true;
                    break;
                case AppFinderStatus.DownloadingProgress:
                    progressBar1.Value = e.ProgressPercentage;
                    break;
            }
        }

        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            _helper.Update += OnUpdate;
            _helper.DoWork();
        }

        void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var eventArgs = e.UserState as AppFinderHelperEventArgs;
            if (eventArgs == null)
                return;

            switch (eventArgs.Status)
            {
                case AppFinderStatus.SearchingForInstallion:
                    label2.Text = "Searching for previously installed version...";
                    progressBar1.Value = 0;
                    break;
                case AppFinderStatus.InstallationFound:
                    label2.Text = "Installation found.";
                    progressBar1.Value = 100;
                    button1.Enabled = false;
                    InstalledPath = eventArgs.Message;
                    IsComplete = true;
                    break;
                case AppFinderStatus.InstallationCanceledByUser:
                    label2.Text = "Canceled by you";
                    button1.Enabled = false;
                    break;
            }
        }

        void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                var process = Process.Start(ApplicationInfo.TemporaryFileName);
                if (process != null)
                    process.WaitForExit();
            }
            catch (Win32Exception win32Exception)
            {
                if (win32Exception.ErrorCode == TheOperationWasCanceledByTheUser)
                {
                    ReportProgressTwo(AppFinderStatus.InstallationCanceledByUser);
                }
            }

            if (_helper.IsInstalled())
            {
                ReportProgressTwo(AppFinderStatus.InstallationFound, _helper.GetInstallationPath());
            }
        }

        void OnUpdate(object sender, AppFinderHelperEventArgs e)
        {
            backgroundWorker1.ReportProgress(e.Progress, e);
        }

        void OnCancel(object sender, EventArgs e) { }

        private void button1_Click(object sender, EventArgs e)
        {
            if (needInstallation)
            {
                DoInstall();
            }
            else
            {
                DoCancel();
            }
        }

        private void DoInstall()
        {
            backgroundWorker2.RunWorkerAsync();
        }

        private void ReportProgress(AppFinderStatus status)
        {
            backgroundWorker1.ReportProgress(0, new AppFinderHelperEventArgs { Status = status });
        }

        private void ReportProgressTwo(AppFinderStatus status, string message = null)
        {
            backgroundWorker2.ReportProgress(0, new AppFinderHelperEventArgs { Status = status, Message = message });
        }

        private void DoCancel()
        {
            var cancelDialog = new AppFinder_CancelForm();
            switch (cancelDialog.ShowDialog(this))
            {
                case DialogResult.None:
                    break;
                case DialogResult.OK:
                    break;
                case DialogResult.Cancel:
                    break;
                case DialogResult.Abort:
                    _helper.Cancel();
                    Cancel(this, new EventArgs());
                    break;
                case DialogResult.Retry:
                    break;
                case DialogResult.Ignore:
                    break;
                case DialogResult.Yes:
                    break;
                case DialogResult.No:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void AppFinder_Load(object sender, EventArgs e)
        {
            if (ApplicationInfo == null)
                return;

            if (!string.IsNullOrEmpty(ApplicationInfo.ApplicationName))
                label1.Text = ApplicationInfo.ApplicationName;
            linkLabel1.Links.Add(0, linkLabel1.Text.Length);
        }

        public void Start()
        {
            _helper = new AppFinderHelper { Info = ApplicationInfo };
            backgroundWorker1.RunWorkerAsync();
        }
    }
}